home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / SciAn / src / ScianTypes.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  44KB  |  1,982 lines

  1. #include "Scian.h"
  2. #include "ScianTypes.h"
  3. #include "ScianIDs.h"
  4. #include "ScianLists.h"
  5. #include "ScianColors.h"
  6. #include "ScianErrors.h"
  7. #include "ScianNames.h"
  8. #include "ScianGarbageMan.h"
  9. #include "ScianMethods.h"
  10. #include "ScianArrays.h"
  11. #include "ScianTimers.h"
  12. #include "ScianPictures.h"
  13. #include "ScianWindows.h"
  14. #include "ScianObjWindows.h"
  15. #include "ScianVisWindows.h"
  16. #include "ScianDialogs.h"
  17. #include "ScianComplexControls.h"
  18. #include "ScianDatasets.h"
  19. #include "ScianVisObjects.h"
  20. #include "ScianScripts.h"
  21. #include "ScianSockets.h"
  22. #include "ScianNetObjects.h"
  23.  
  24. /*TEMPORARY*/
  25. Bool    Equal(ObjPtr obj1, ObjPtr obj2);
  26.  
  27. char *whatsMyName = "SciAn";
  28.  
  29. long int createdObjects = 0;
  30.  
  31. unsigned long anotherDamnReferenceCount = 0;
  32.  
  33. /* ComparePtrs returns true iff two pointers address the same location */
  34. #define ComparePtrs(obj1,obj2) ((void *) (obj1) == (void *) (obj2))
  35.  
  36. /* AssignPtr assigns one pointer to another regardless of types pointed to */
  37. #define AssignPtr(p1,p2) ((void *) (p1) = (void *) (p2))
  38.  
  39. #define DELSTAGE0 0
  40. #define DELSTAGE1 1
  41. #define DELSTAGE2 2
  42.  
  43. ObjPtr objClass = 0;
  44. ObjPtr stringClass;
  45. ObjPtr ObjTrue;
  46. ObjPtr ObjFalse = NULLOBJ;
  47.  
  48. long globalThingCount=0;
  49. long globalRefCount = 0;
  50.  
  51. /**-- Statistics stuff */
  52.  
  53. #ifndef STATSFILENAME
  54. #define STATSFILENAME "scianStatistics"
  55. #endif
  56.  
  57. FILE *statsFile = 0;
  58.  
  59. struct {
  60.     long getvar;
  61.     long setvar;
  62.     long changevar;
  63. } statsArray[MAXIDNUM];
  64.  
  65. int trackStatistics = 0;
  66.  
  67. int debugCountObjects = 0;
  68.  
  69. /* this stuff only used when debugCountObjects is set to true */
  70. unsigned long maxExtra = 0;
  71.  
  72. #define MAXEXTRA 1024
  73. long int *extras; /* pointer to block of counts for each size obj. */
  74.  
  75. void PrintStatisticsTree(node)
  76. NameNodePtr node;
  77. {
  78.     if (!node) return;
  79.     PrintStatisticsTree(node->left);
  80.     if (statsArray[node->id].getvar || statsArray[node->id].setvar ||
  81.     statsArray[node->id].changevar)
  82.     {
  83.     fprintf(statsFile, "%-8ld GetVar, %-8ld SetVar, %-8ld ChangeVar %s\n",
  84.         statsArray[node->id].getvar, statsArray[node->id].setvar,
  85.         statsArray[node->id].changevar, GetInternalString(node->id));
  86.     }
  87.     PrintStatisticsTree(node->right);
  88. }
  89.  
  90. int iteration = 0;
  91.  
  92. void PrintStatistics()
  93. {
  94.     fprintf(statsFile, "#### PrintStatistics iteration %d\n", iteration++);
  95.     PrintStatisticsTree(IDsTree);
  96. }
  97.  
  98. void ClearStatistics()
  99. {
  100.     int i;
  101.  
  102.     for (i = 0; i < MAXIDNUM; ++i)
  103.     {
  104.     statsArray[i].getvar = 0;
  105.     statsArray[i].setvar = 0;
  106.     }
  107. }
  108.  
  109. void TurnOnStatistics()
  110. {
  111.     if (!statsFile)
  112.     {
  113.     statsFile = fopen (STATSFILENAME, "w");
  114.     if (!statsFile)
  115.     {
  116.         Error("TurnOnStatistics Internal Error", OPENFILEERROR, STATSFILENAME);
  117.         statsFile = stderr;
  118.     }
  119.     }
  120.     trackStatistics = 1;
  121. }
  122.  
  123. void TurnOffStatistics()
  124. {
  125.     trackStatistics = 0;
  126. }
  127.  
  128. /**-- miscellaneous junk */
  129.  
  130. Bool IsTrue(obj)
  131. ObjPtr obj;
  132. {
  133.     return obj && IsInt(obj) && GetInt(obj);
  134. }
  135.  
  136. ObjPtr SetObjValue(obj, value)
  137. ObjPtr obj, value;
  138. {
  139.     ObjPtr oldvalue;
  140.     ObjPtr retVal;
  141.  
  142.     oldvalue = GetVar(obj, VALUE); /* Note: NOT GetValue */
  143.     SetVar(obj, VALUE, value);
  144.     if(!Eql(value, oldvalue))
  145.     {
  146.     ChangedValue(obj);
  147.     retVal = ObjTrue;
  148.     }
  149.     else
  150.     {
  151.     retVal = ObjFalse;
  152.     }
  153.  
  154.     ImInvalid(obj);
  155.     if (logging) LogControl(obj);
  156.  
  157.     return retVal;
  158. }
  159.  
  160. ObjPtr GetObjValue(obj)
  161. ObjPtr obj;
  162. {
  163.     return GetVar(obj, VALUE);
  164. }
  165.  
  166. ObjPtr        NewObject(class, extra)
  167. ObjPtr        class;
  168. unsigned long extra;
  169. /* NewObject:    creates a new object of class class. if <extra> is non-
  170.                 zero, <extra> bytes are tacked onto the end of the object,
  171.                 for some unknown use. The vars list is nil, the flags have
  172.                 only the Object bit set. returns:pointer to the new object */
  173. {
  174.     ObjPtr    newThing;
  175.  
  176.     if (debugCountObjects)
  177.     {
  178.     if (maxExtra < extra) maxExtra = extra;
  179.     if (extra < MAXEXTRA - 1)
  180.         ++(*(extras + extra));
  181.     else
  182.         ++(*(extras + MAXEXTRA - 1));
  183.     }
  184.  
  185.     if (!(newThing = (ObjPtr) Alloc(sizeof(Obj) + extra) ))
  186.     {
  187.     OMErr();
  188.     return (ObjPtr) NIL;
  189.     }
  190.     newThing -> flags = 0;
  191.     SETOBJTYPE(newThing -> flags, PLAINOBJECT);
  192.     /* newThing->refCount = 0; */
  193.     if (class)
  194.     {
  195.     newThing->class = class;
  196.     }
  197.     else
  198.     {
  199.     newThing->class = objClass;
  200.     }
  201.     newThing->vars = (VarsPtr) NIL;
  202.     newThing->methods = (MethodPtr) NIL;
  203.     newThing->depends = (DependPtr) NIL;
  204.     IncGlobalThingCount();
  205.  
  206.     /* newThing->rNext = NULLOBJ; */
  207.     newThing->garbageFlag = DELSTAGE0;
  208.     AddToGlobalList(newThing);
  209.     ++createdObjects;
  210.     return newThing;
  211. }
  212.  
  213. ObjPtr    ClassOf(object)
  214. ObjPtr    object;
  215. {
  216.     return object->class;
  217. }
  218.  
  219. VarsPtr    NewVarsNode(name,value)
  220. NameTyp    name;
  221. ObjPtr    value;
  222. /* NewVarsNode:    creates a new node for the internal vars list (binary tree)
  223.     of an object. Sets ->name to name, ->value to value, tree
  224.     pointers to NIL, chCount to something. Returns pointer to new node. */
  225. {
  226.     VarsPtr    theVar;
  227.  
  228.     if (!( theVar = (VarsPtr) Alloc(sizeof(Vars)) ))
  229.     {
  230.     OMErr();
  231.     return (VarsPtr) NIL;
  232.     }
  233.     theVar->name = name;
  234.     theVar->value = value;
  235.     theVar->left = (struct VarsNode *) NIL;
  236.     theVar->right = (struct VarsNode *) NIL;
  237.     theVar->chCount = ++anotherDamnReferenceCount;
  238.  
  239.     theVar->process = NULLOBJ;
  240.     theVar->remoteChCount = 0;
  241.     theVar->remoteNetID = 0;
  242.  
  243.  
  244.     if (anotherDamnReferenceCount == 0xFFFFFFFFL)
  245.     {
  246.     ReportError("NewVarsNode", "Eric is a liar!");
  247.     }
  248.     return theVar;
  249. }
  250.  
  251.  
  252. #ifdef PROTO
  253. VarsPtr ResetVarsNode(VarsPtr vptr, ObjPtr value)
  254. #else
  255. VarsPtr ResetVarsNode(vptr, value)
  256. VarsPtr vptr;
  257. ObjPtr value;
  258. #endif
  259. /* Changes the value of a var. Resets value-associated things (changecount, remote
  260.  * stuff) but leaves the var tree connectivity stuff (left, right pointers) alone.
  261.  */
  262. {
  263.     vptr -> value = value;
  264.     vptr -> chCount = ++anotherDamnReferenceCount;
  265.     if (anotherDamnReferenceCount == 0xFFFFFFFFL)
  266.     {
  267.     ReportError("ResetVarsNode", "Eric is a liar!");
  268.     }
  269.     
  270.     vptr -> remoteNetID = 0;
  271.     vptr -> remoteChCount = 0;
  272.     vptr -> process = NULLOBJ;
  273.  
  274. }
  275.  
  276. VarsPtr GetVarNode(obj, var)
  277. ObjPtr obj;
  278. NameTyp var;
  279. /* GetVarNode: instead of returning the value of <var> in <obj>, this returns
  280.  * a pointer to the var node. So, disregarding weirdnesses like Distributed
  281.  * Objects, "foo = GetVarNode(obj, var); bar = foo -> value;" is equivalent
  282.  * to "bar = GetVar(obj, var);" . Really!!
  283.  */
  284. {
  285.     VarsPtr tester;
  286.  
  287.     while (obj)
  288.     {
  289.     tester = obj -> vars;
  290.     while (tester)
  291.     {
  292.         if (var == tester->name)
  293.         {
  294.         /* found it */
  295.         return tester;
  296.         }
  297.         else
  298.         {
  299.         if (var > tester->name)
  300.         {
  301.             tester = tester -> right;
  302.         }
  303.         else /* var < tester -> name */
  304.         {
  305.             tester = tester -> left;
  306.         }
  307.         }
  308.     }
  309.     /* not found, traverse up class hierarchy */
  310.     obj = obj -> class;
  311.     }
  312.  
  313.     /* not found */
  314.     return (VarsPtr) 0;
  315. }
  316.  
  317. /* returns true if obj1/var1 'older' than obj2/var2 (i.e. chCt 1 < chCt 2) */
  318. Bool CompareVarChangeCounts(obj1, var1, obj2, var2)
  319. ObjPtr obj1, obj2;
  320. NameTyp var1, var2;
  321. /* NOTE: obj1/var1 dependent on obj2/var2 */
  322. {
  323.     unsigned long chCount1, chCount2;
  324.     VarsPtr vnode1, vnode2;
  325.  
  326.     vnode1 = GetVarNode(obj1, var1);
  327.     vnode2 = GetVarNode(obj2, var2);
  328.  
  329.     if (!vnode1)
  330.     {
  331.     return true;
  332.     }
  333.  
  334.     if (!vnode2)
  335.     {
  336.     return false;
  337.     }
  338.  
  339.     if (vnode1 -> remoteNetID && vnode2 -> remoteNetID)
  340.     {
  341.     if ((vnode1 -> remoteNetID == NETSTUBFLAG) || (vnode2 -> remoteNetID == NETSTUBFLAG))
  342.     {
  343.         return false;
  344.     }
  345.     return vnode1 -> remoteChCount < vnode2 -> remoteChCount;
  346.     }
  347.     else
  348.     {
  349.     return vnode1 -> chCount < vnode2 -> chCount;
  350.     }
  351. }
  352.  
  353. unsigned long GetVarChangeCount(object, varname)
  354. ObjPtr object;
  355. NameTyp varname;
  356. {
  357.     VarsPtr tester;
  358.  
  359.     if (!object)
  360.     {
  361.     return 0;
  362.     }
  363.  
  364.     tester = object->vars;
  365.     while (tester)
  366.     {
  367.     if (varname == tester->name)
  368.     {
  369.         /* found it */
  370. #ifdef SOCKETS
  371.         if (tester->remoteNetID && !ThisWouldBeAReallyBadThing(varname))
  372.         {
  373.         ObjPtr remote;
  374.  
  375.         if (tester -> remoteNetID == NETSTUBFLAG)
  376.         {
  377. #if 0
  378. fprintf(stderr, "SendGetVarMessage from GetVarChangeCount (Netid == NETSTUBFLAG)\n");
  379.             /* has never been retrieved yet */
  380.             SendGetVarMessage(object, varname);
  381.             WaitForNetObjectVar(object, tester);
  382.             return tester->remoteChCount;
  383. #else
  384.             return anotherDamnReferenceCount + 1;
  385. #endif
  386.         }
  387.  
  388.         remote = FindRemoteObject(tester -> process, tester -> remoteNetID, false);
  389.         if (remote)
  390.         {
  391.             return tester -> remoteChCount;
  392.         }
  393.         else
  394.         {
  395.             /* not sure if correct, but it seems to work */
  396.             return anotherDamnReferenceCount + 1;
  397.         }
  398.         }
  399. #endif
  400.         return tester->chCount;
  401.     }
  402.     else
  403.     {
  404.         if (varname > tester->name)
  405.         {
  406.         tester = tester -> right;
  407.         }
  408.         else /* varname < tester -> name */
  409.         {
  410.         tester = tester -> left;
  411.         }
  412.     }
  413.     }
  414.     /* wasn't found, try the class of the object */
  415.     return GetVarChangeCount(object->class, varname);
  416. }
  417.  
  418. ObjPtr        SetVar(object,varname,value)
  419. ObjPtr        object;
  420. ObjPtr        value;
  421. NameTyp        varname;
  422. /* SetVar: Associates varname with value in object object. If an 
  423.  * association of varname existed previously, SetVar updates it.
  424.  * If not, SetVar creates a new one in the object's var list
  425.  * SIDE EFFECT: SetVar always updates anotherDamnReferenceCount
  426.  *
  427.  * Modified 10-15-91 John Murray
  428.  *     Returns the value which the variable was set to, or ObjFalse
  429.  */
  430. {
  431.     VarsPtr    tester;
  432.     int        notfound;
  433.  
  434.     if (trackStatistics)
  435.     {
  436.     ++statsArray[varname].setvar;
  437.     }
  438.  
  439.     if (!object)
  440.     {
  441.     return ObjFalse;
  442.     }
  443.  
  444. /* #ifndef RELEASE */
  445.     if ( (!SanityCheckObject(object)) || (!SanityCheckObject(value)))
  446.     {
  447.     return ObjFalse;
  448.     }
  449. /* #endif */
  450.  
  451.     /* search for variable in object->vars */
  452.     notfound = true;
  453.     tester = object->vars;
  454.     if ( ! object->vars)
  455.     {
  456.     object->vars = NewVarsNode(varname,value); /* add first node */
  457.     return value;
  458.     }
  459.     while(notfound)
  460.     {
  461.     /* shouldn't find the net stub down in the tree. (bad thing if we do) */
  462.     if (varname == tester->name)
  463.     {
  464.  
  465. #ifdef SOCKETS
  466.         /* if the object and old value are published, notify about update */
  467.         if (/*IsPublished(tester -> value) && */IsPublished(object))
  468.         {
  469. #ifdef DEBUG
  470. fprintf(stderr, "sending update notice for var %s\n",
  471.     GetInternalString(tester -> name));
  472. #endif
  473.         SendVarUpdateNotice(object, tester -> name);
  474.         }
  475. #endif
  476.  
  477.         notfound = false;
  478.         ResetVarsNode(tester, value);
  479.     }
  480.     else if (varname > tester->name)
  481.     {
  482.         if (tester->right)
  483.         tester = tester->right;
  484.         else                /* add node right */
  485.         {
  486.         tester->right = NewVarsNode(varname,value);
  487.         notfound = false;
  488.         }
  489.     }
  490.     else                /* varname < tester->name */
  491.     {
  492.         if (tester->left)
  493.         tester = tester->left;
  494.         else                /* add node left */
  495.         {
  496.         tester->left = NewVarsNode(varname,value);
  497.         notfound = false;
  498.         }
  499.     }
  500.     }
  501.     return value;
  502. }
  503.  
  504. Bool        ChangeVar(object,varname,value)
  505. ObjPtr        object;
  506. ObjPtr        value;
  507. NameTyp        varname;
  508. /* ChangeVar:    Associates varname with value in object object. If an 
  509.         association of varname existed previously, ChangeVar updates it.
  510.         If not, ChangeVar creates a new one in the object's var list 
  511.         IF AND ONLY IF the old and new values are not Equal(). 
  512.         SIDE EFFECT: may or may not change anotherDamnReferenceCount */
  513. {
  514.     VarsPtr    tester;
  515.     int        notfound = true;
  516.     Bool    retVal;
  517.  
  518.     if (!object)
  519.     {
  520.     return false;
  521.     }
  522.  
  523. #if 0
  524.     if (IsNetwork(object))
  525.     {
  526.     fprintf(stderr, "ChangeVar on Network object\n");
  527.     return false;
  528.     }
  529. #endif
  530.  
  531.     if (IsRemote(object))
  532.     {
  533.     fprintf(stderr, "ChangeVar on Remote object... NOT!\n");
  534.     return false;
  535.     }
  536.  
  537.     /* search for variable in object->vars */
  538.     if ( ! object->vars)
  539.     {
  540.     /* add first node */
  541.     object->vars = NewVarsNode(varname,value);
  542.     if (Equal(GetVar(ClassOf(object), varname), value))
  543.     {
  544.         --anotherDamnReferenceCount;
  545.         object->vars->chCount = GetVarChangeCount(ClassOf(object), varname);
  546.         retVal = false;
  547.     }
  548.     else
  549.     {
  550.         retVal = true;
  551.     }
  552.     return retVal;
  553.     }
  554.  
  555.     tester = object->vars;
  556.     while(notfound)
  557.     {
  558.     if (varname == tester->name)
  559.     {
  560.  
  561. if (tester -> remoteNetID)
  562.     fprintf(stderr, "WARNING! ChangeVar superseding remote value (netid %ld) of %s\n", tester -> remoteNetID, IDName(varname));
  563.  
  564. #if 0
  565.         if (IsNetwork(tester->value))
  566.         {
  567.         fprintf(stderr, "ChangeVar: value of var is Network object\n");
  568.         return false;
  569.         }
  570. #endif
  571.  
  572.         if (IsRemote(tester -> value))
  573.         {
  574.         fprintf(stderr, "ChangeVar value of variable is Remote\n");
  575.         return false;
  576.         }
  577.  
  578.         if (Equal(GetVar(object, varname), value))
  579.         {
  580.         tester->value = value;
  581.         retVal = false;
  582.         }
  583.         else
  584.         {
  585.         ResetVarsNode(tester, value);
  586.         retVal = true;
  587.         }
  588.         notfound = false;
  589.     }
  590.     else if (varname > tester->name)
  591.     {
  592.         if (tester->right)
  593.         tester = tester->right;
  594.         else                /* add node right */
  595.         {
  596.                 tester->right = NewVarsNode(varname,value);
  597.         if (Equal(GetVar(ClassOf(object), varname), value))
  598.         {
  599.             /* trust me, I know what I'm doing... */
  600.             --anotherDamnReferenceCount;
  601.             tester->right->chCount = GetVarChangeCount(ClassOf(object), varname);
  602.             retVal = false;
  603.         }
  604.         else
  605.         {
  606.             retVal = true;
  607.         }
  608.         notfound = false;
  609.         }
  610.     }
  611.     else                /* varname < tester->name */
  612.     {
  613.         if (tester->left)
  614.         tester = tester->left;
  615.         else                /* add node left */
  616.         {
  617.                 tester->left = NewVarsNode(varname,value);
  618.         if (Equal(GetVar(ClassOf(object), varname), value))
  619.         {
  620.             /* trust me, I know what I'm doing... */
  621.             --anotherDamnReferenceCount;
  622.             tester->left->chCount = GetVarChangeCount(ClassOf(object), varname);
  623.             retVal = false;
  624.         }
  625.         else
  626.         {
  627.             retVal = true;
  628.         }
  629.         notfound = false;
  630.         }
  631.     }
  632.     }
  633.     return retVal;
  634. }
  635.  
  636. void    CloneVarTreeInternal(obj, tree)
  637. ObjPtr    obj;
  638. VarsPtr    tree;
  639. {
  640.     if (tree)
  641.     {
  642.     if (tree -> remoteNetID)
  643.     {
  644.         VarsPtr vptr;
  645.  
  646.         SetVar(obj, tree->name, NULLOBJ); /* can't SetVar to the value, might be bad */
  647.         vptr = GetVarNode(obj, tree->name);
  648.         vptr -> process = tree -> process;
  649.         vptr -> remoteNetID = tree -> remoteNetID;
  650.         vptr -> remoteChCount = tree -> remoteChCount;
  651.         vptr -> value = tree -> value;
  652.     }
  653.     else
  654.     {
  655.         SetVar(obj, tree->name, tree->value);
  656.     }
  657.  
  658.     CloneVarTreeInternal(obj, tree->left);
  659.     CloneVarTreeInternal(obj, tree->right);
  660.     }
  661. }
  662.  
  663. void    CloneVars(target, src)
  664. ObjPtr    target, src;
  665. {
  666.     CloneVarTreeInternal(target, src->vars);
  667. }
  668.  
  669. #ifdef SOCKETS
  670. ObjPtr gviRetVal; /* I'm paranoid (not needed for non-sockets, returns &(t->v)*/
  671. #endif
  672.  
  673. ObjPtr    *GetVarInternal(object,varname)
  674. ObjPtr        object;
  675. NameTyp       varname;
  676. /* GetVarInternal: returns the value with which a varname is associated within
  677.     object. Returns NIL if no association was found in object */
  678. /* NOTE: Currently there is no mechanism for undefining a name other than
  679.     defining it to be NIL. This means there is no way to redefine a name
  680.     back to a class definition when it has been defined locally. */
  681. /* June 16, 1992 Changed to return the pointer to the vars node
  682.     instead of the pointer to the value of the vars node. (Note that
  683.     returning a NIL varsptr implies no existing definition, while returning
  684.     a valid varsptr whose value is NIL implies an existing definition
  685.     of NIL) Also made non-recursive. Class traversal moved to GetVar. */
  686. /* Sept 30, 1992 Changed to return a handle (pointer to ObjPtr) instead of VarsPtr*/ 
  687. {
  688.     VarsPtr    tester;
  689.  
  690.     if (!object)
  691.     {
  692.     return (ObjPtr *) 0;
  693.     }
  694.  
  695.     /* search for variable in object->vars */
  696.     tester = object->vars;
  697.     while(tester)
  698.     {
  699.     if (tester->name == varname)
  700.     {
  701. #ifdef SOCKETS
  702.         if (tester -> remoteNetID)
  703.         {
  704.         if (tester -> remoteNetID == NETSTUBFLAG)
  705.         {
  706.             /*never been retrieved yet */
  707. #ifdef DEBUG
  708. fprintf(stderr, "SendGetVarMessage from GetVarInternal\n");
  709. #endif
  710.             SendGetVarMessage(object, varname);
  711.             WaitForNetObjectVar(object, tester);
  712.             tester = GetVarNode(object, varname);
  713. #ifdef PARANOID
  714.             if (tester -> remoteNetID == NETSTUBFLAG)
  715.             {
  716.             ReportError("GetVarInternal", "internal error (probably network timeout)");
  717.             }
  718. #endif
  719.             gviRetVal = FindRemoteObject(tester -> process, tester -> remoteNetID, false);
  720.             if (gviRetVal && !tester -> value)
  721.             {
  722.             tester -> value = gviRetVal;
  723.             }
  724.             return &gviRetVal;
  725.         }
  726.  
  727.         else if (!tester -> value)
  728.         {
  729.             /* netid != 0 and netid != NETSTUBFLAG, so we must have a copy of it.. */
  730.             gviRetVal = FindRemoteObject(tester -> process, tester -> remoteNetID, true);
  731.             return &gviRetVal;
  732.         }
  733.         else
  734.         {
  735.             if (IsDefunct(tester -> value))
  736.             {
  737. fprintf(stderr, "re-getting defunct object\n");
  738.             SendGetVarMessage(object, varname);
  739.             WaitForNetObjectVar(object, tester);
  740.             tester = GetVarNode(object, varname);
  741. #ifdef PARANOID
  742.             if (IsDefunct(tester -> value))
  743.             {
  744.                 ReportError("GetVarInternal", "internal error (timed out waiting for defunct obj)");
  745.             }
  746. #endif
  747.             gviRetVal = FindRemoteObject(tester -> process, tester -> remoteNetID, false);
  748.             if (gviRetVal)
  749.             {
  750.                 tester -> value = gviRetVal;
  751.             }
  752.             return &gviRetVal;
  753.             }
  754.             else
  755.             {
  756.             return &(tester -> value);
  757.             }
  758.         }
  759.         }
  760. #endif
  761.         return &(tester -> value);
  762.     }
  763.     else if (varname > tester->name)
  764.         tester = tester->right;
  765.     else                /* varname < tester->name */
  766.         tester = tester->left;
  767.     }
  768.     /* var wasn't found */
  769.     return (ObjPtr *) 0;
  770. }
  771.  
  772. ObjPtr GetVar(object,varname)
  773. ObjPtr        object;
  774. NameTyp        varname;
  775. /* Searches for a variable in an object. Searches up the class hierarchy if
  776.  * no variable value was found.
  777.  */
  778. {
  779.     ObjPtr *handle;
  780.  
  781.     if (!object)
  782.     {
  783.     return NULLOBJ;
  784.     }
  785.  
  786.     if (trackStatistics)
  787.     {
  788.     ++statsArray[varname].getvar;
  789.     }
  790.  
  791.     /* search for var, if necessary up the obj's class hierarchy until found */
  792.     while (! (handle = GetVarInternal(object, varname)))
  793.     {
  794.     if (!object->class)
  795.         break;
  796.     object = object->class;
  797.     }
  798.  
  799.     if (handle)
  800.     return *handle;
  801.     else
  802.     return NULLOBJ;
  803. }
  804.  
  805. ObjPtr    Get1Var(object, varname)
  806. ObjPtr        object;
  807. NameTyp        varname;
  808. /* Get1Var:    returns the value with which a varname is associated within
  809.     object, [ not the object's class ]. Returns NIL if no
  810.     association was found in object*/
  811. /* NOTE: Currently there is no mechanism for undefining a name other than
  812.     defining it to be NIL. This means there is no way to redefine a name
  813.     back to a class definition when it has been defined locally. */
  814. {
  815.     ObjPtr *handle;
  816.  
  817.     if (!object)
  818.     {
  819.     return NULLOBJ;
  820.     }
  821.  
  822.     if (trackStatistics)
  823.     {
  824.     ++statsArray[varname].getvar;
  825.     }
  826.  
  827.     /* search for var. This time, don't search the class hierarchy */
  828.  
  829.     handle = GetVarInternal(object, varname);
  830.     if (handle)
  831.     return *handle;
  832.     else
  833.     return NULLOBJ;
  834. }
  835.  
  836. /**-- miscellaneous debug-type print routines */
  837.  
  838. void    PrintThing(thingp)
  839. ObjPtr    thingp;
  840. {
  841.     int    k;
  842.  
  843.     if (!thingp)
  844.     {
  845.     printf("Nil thing.\n");
  846.     return;
  847.     }
  848.     printf("Non-nil thing. thingp=0x%lx, ->flags=0x%lx\n",
  849.         thingp, thingp->flags);
  850.     switch(OBJTYPE(thingp->flags))
  851.     {
  852.     case ISOBJECT:
  853.         printf("object.\n");
  854.         PrintObject((ObjPtr) thingp);
  855.         PrintVarTree((ObjPtr) thingp);
  856.         break;
  857.     case REALARRAY:
  858.         printf("RealArray. RANK = %d, DIMS=", RANK(thingp));
  859.         for (k = 0; k < RANK(thingp); ++k)
  860.         printf(k == 0 ? "%ld" : ", %ld", DIMS(thingp)[k]);
  861.         printf(".\n");
  862.         /* PrintArray((ArrayPtr) thingp); */
  863.         break;
  864.     case STRING:
  865.         printf("String.\n");
  866.         PrintString(thingp);
  867.         break;
  868.     case INTEGER:
  869.         printf("Int.\n");
  870.         PrintInt(thingp);
  871.         break;
  872.     case REAL:
  873.         printf("Real.\n");
  874.         PrintReal(thingp);
  875.         break;
  876.     case LIST:
  877.         printf("List. Don't know how to print it.\n");
  878.         break;
  879.     case PALETTE:
  880.         printf("Palette. Don't know how to print it.\n");
  881.         break;
  882.     default:
  883.         break;
  884.     }
  885. }
  886.  
  887. void    PrintObject(object)
  888. ObjPtr    object;
  889. /* PrintObject:    print out in hex the object's address, the object's flags,
  890.     var tree ptr, class ptr, and in decimal, its name. */
  891. {
  892.     printf("&struct = 0x%lx\t",(long) object);
  893.     if (object)
  894.     {
  895.     printf("o->flags = 0x%lx\t",object->flags);
  896.     printf("o->class = 0x%lx\t",(long) object->class);
  897.     printf("o->vars = 0x%lx\t",(long) object->vars);
  898.     printf("o->methods = 0x%lx\n",(long) object->methods);
  899.     }
  900.     else
  901.     printf("not object.\n");
  902. }
  903.  
  904. void    PrintVarNodes(vp, indent)
  905. VarsPtr    vp;
  906. int        indent;
  907. /* PrintVarNodes:    Internal. Print a var node's varname, and the
  908.     associated value (ptr), and print its children, recursively*/
  909. {
  910.     int i;
  911.  
  912.     if (!vp) return;
  913.     PrintVarNodes(vp->left, indent);
  914.     for(i=0; i<indent; ++i)
  915.     putchar(' ');
  916.     printf("id=%s, &value=0x%lx, ", GetInternalString(vp->name), (long)vp->value);
  917.     if (vp->value)
  918.     printf("value->flags = 0x%lx\n", vp->value->flags);
  919.     else
  920.     printf("(no flags)\n");
  921.     PrintVarNodes(vp->right, indent);
  922. }
  923.  
  924. void    PrintVarTree(object)
  925. ObjPtr    object;
  926. /* PrintVarTree:    Print all of the associations of variable names with
  927.     values in an object. Does not print associations of object's
  928.     class. */
  929. {
  930.     if (!object)
  931.     {
  932.     printf("  PrintVarTree: passed NIL object pointer!\n");
  933.     return;
  934.     }
  935.     printf("  Printing vars for object %lx\n",object);
  936.     PrintVarNodes(object->vars, 4);
  937.     printf("  end of vars for object #%lx\n",object);
  938. }
  939.  
  940. /**-- Thing deletion system. reference counts also maintained by SetVar */
  941.  
  942. /* defined in ScianTypes.h */
  943. /* #define GetRefCount(thingp) ((thingp) ? (thingp) -> refCount : -1) */
  944.  
  945. #ifdef PROTO
  946. long IncRefCount(ObjPtr thingp)
  947. #else
  948. long IncRefCount(thingp)
  949. ObjPtr thingp;
  950. #endif
  951. {
  952.     AddToReferenceList(thingp);
  953.     return 0;
  954. }
  955.  
  956. void    DecGlobalThingCount()
  957. {
  958.     --globalThingCount;
  959.     if (globalThingCount < 0)
  960.     {
  961.     ReportError("DecGlobalThingCount", "globalThingCount negative!");
  962.     }
  963. }
  964.  
  965. void        DeleteVarNode(nodep)
  966. VarsPtr        nodep;        /* pointer to node to delete */
  967. /* DeleteVarNode:    frees space allocated to a var node and all its kids */
  968. {
  969.     if (!nodep) return;
  970.     DeleteVarNode(nodep->left);
  971.     DeleteVarNode(nodep->right);
  972.     Free(nodep);
  973. }
  974.  
  975. void        DeleteMethodNode(nodep)
  976. MethodPtr    nodep;        /* pointer to node to delete */
  977. /* DeleteMethodNode:    frees space allocated to a method node and its kids */
  978. {
  979.     if (!nodep) return;
  980.     DeleteMethodNode(nodep->left);
  981.     DeleteMethodNode(nodep->right);
  982.     Free(nodep);
  983. }
  984.  
  985. int deleteCount=0;
  986. int trivialDeleteCount=0;
  987. int noDeleteCount=0;
  988. int missedDeleteCount=0;
  989.  
  990. void        DeleteThing(thingp)
  991. ObjPtr    thingp;
  992. /* DeleteThing: an archaic routine whose function has been superseded.
  993.  */
  994.  
  995. {
  996.     RemoveFromReferenceList(thingp);
  997.     return;
  998. }
  999.  
  1000. /**-- Methods routines */
  1001.  
  1002. FuncTyp        GetMethod(object,methname)
  1003. ObjPtr        object;
  1004. NameTyp        methname;
  1005. /* GetVar:    returns the value with which a methname is associated within
  1006.  * object, or objects class, recursively. Returns NIL if no
  1007.  * association was found in object or its classes.
  1008.  */
  1009. /* July 9, 1992 John R. Murray. GetMethod showed up at the top of the profile
  1010.  * report I just ran, so let's try to make it faster. Making it non-recursive.
  1011.  */
  1012. {
  1013.     ObjPtr thing;
  1014.     MethodPtr    tester;
  1015.  
  1016.     /* search for variable in object->methods */
  1017.  
  1018.     thing = object;
  1019.     while (thing)
  1020.     {
  1021.     tester = thing->methods;
  1022.     while(tester)
  1023.     {
  1024.         if (tester->name == methname)
  1025.         return tester->method;
  1026.         else if (methname > tester->name)
  1027.         tester = tester->right;
  1028.         else                /* methname < tester->name */
  1029.         tester = tester->left;
  1030.     }
  1031.  
  1032.     /* didn't find it. Let's try its class */
  1033.     thing = ClassOf(thing);
  1034.     }
  1035.     /* didn't find method in object or object's classes (or object was 0) */
  1036.     return (FuncTyp) 0;
  1037. }
  1038.  
  1039. FuncTyp        Get1Method(object,methname)
  1040. ObjPtr        object;
  1041. NameTyp        methname;
  1042. /* GetVar:    returns the value with which a methname is associated within
  1043.         object, [ not the object's class ]. Returns NIL if no
  1044.         association was found in object */
  1045. {
  1046.     MethodPtr    tester;
  1047.  
  1048.     if (!object)
  1049.     {
  1050.     return (FuncTyp) 0;
  1051.     }
  1052.  
  1053.     /* search for variable in object->methods */
  1054.     tester = object->methods;
  1055.     while(tester)
  1056.     {
  1057.     if (tester->name == methname)
  1058.         return tester->method;
  1059.     else if (methname > tester->name)
  1060.         tester = tester->right;
  1061.     else                /* methname < tester->name */
  1062.         tester = tester->left;
  1063.     }
  1064.     /* method wasn't found, so return "nil" */
  1065.     return (FuncTyp) 0;
  1066. }
  1067.  
  1068. MethodPtr    NewMethodsNode(name,method)
  1069. NameTyp        name;
  1070. FuncTyp        method;
  1071. /* NewVarsNode:    creates a new node for the internal vars list (binary tree)
  1072.     of an object. Sets ->name to name, ->method to method, tree
  1073.     pointers to NIL. Returns pointer to new node. */
  1074. {
  1075.     MethodPtr    theMethod;
  1076.  
  1077.     if (!( theMethod = (MethodPtr) Alloc(sizeof(Method)) ))
  1078.     {
  1079.     OMErr();
  1080.     return (MethodPtr) NIL;
  1081.     }
  1082.     theMethod->name = name;
  1083.     theMethod->method = method;
  1084.     theMethod->left = (MethodPtr) NIL;
  1085.     theMethod->right = (MethodPtr) NIL;
  1086.     return theMethod;
  1087. }
  1088.  
  1089. Bool        SetMethod(object,methodname,value)
  1090. ObjPtr        object;
  1091. NameTyp        methodname;
  1092. FuncTyp        value;
  1093. /* SetMethod:    Associates methodname with function in object object. If an 
  1094.         association of methodname existed previously, SetMethod updates it.
  1095.         If not, SetMethod creates a new one in the object's var list */
  1096. {
  1097.     MethodPtr    tester;
  1098.     int        notfound;
  1099.  
  1100.     if (!object)
  1101.     {
  1102.     return false;
  1103.     }
  1104.  
  1105.     /* search for variable in object->methods */
  1106.     notfound = true;
  1107.     tester = object->methods;
  1108.     if ( ! object->methods)
  1109.     {
  1110.     object->methods = NewMethodsNode(methodname,value); /* add first node */
  1111.     notfound = false;
  1112.     }
  1113.     while(notfound)
  1114.     {
  1115.     if (methodname == tester->name)
  1116.     {
  1117.         notfound = false;
  1118.         tester->method = value;
  1119.     }
  1120.     else if (methodname > tester->name)
  1121.     {
  1122.         if (tester->right)
  1123.         tester = tester->right;
  1124.         else                /* add node right */
  1125.         {
  1126.         tester->right = NewMethodsNode(methodname,value);
  1127.         notfound = false;
  1128.         }
  1129.     }
  1130.     else                /* methodname < tester->name */
  1131.     {
  1132.         if (tester->left)
  1133.         tester = tester->left;
  1134.         else                /* add node left */
  1135.         {
  1136.         tester->left = NewMethodsNode(methodname,value);
  1137.         notfound = false;
  1138.         }
  1139.     }
  1140.     }
  1141.     return true;
  1142. }
  1143.  
  1144. /**-- Dependencies routines */
  1145.  
  1146. void AddDependency(dList, iVar, var)
  1147. DLPtr *dList;
  1148. NameTyp iVar, var;
  1149. {
  1150.     DLPtr newDep, *runner;
  1151.  
  1152.     runner = dList;
  1153.     while(*runner && (*runner) -> var < var && (*runner) -> indirectVar < iVar)
  1154.     {
  1155.     runner = &((*runner) -> next);
  1156.     }
  1157.  
  1158.     if (*runner && (*runner) -> var == var && (*runner) -> indirectVar == iVar)
  1159.     {
  1160.     /* already in list */
  1161.     return;
  1162.     }
  1163.  
  1164.     newDep = Alloc(sizeof(struct DependListEl));
  1165.     newDep -> indirectVar = iVar;
  1166.     newDep -> var = var;
  1167.     newDep -> next = *runner;
  1168.     *runner = newDep;
  1169. }
  1170.  
  1171. DependPtr NewDependNode(var)
  1172. NameTyp var;
  1173. {
  1174.     DependPtr retVal;
  1175.  
  1176.     retVal = Alloc(sizeof(Depend));
  1177.     if (!retVal)
  1178.     {
  1179.     OMErr();
  1180.     return retVal;
  1181.     }
  1182.     retVal -> var = var;
  1183.     retVal -> dependList = (DLPtr) 0;
  1184.     retVal -> left = (struct DependNode *) 0;
  1185.     retVal -> right = (struct DependNode *) 0;
  1186.     return retVal;
  1187. }
  1188.  
  1189. int CountNodes(dNode)
  1190. DependPtr dNode;
  1191. {
  1192.     if (!dNode)
  1193.     return 0;
  1194.     else
  1195.     return 1 + CountNodes(dNode -> left) + CountNodes(dNode -> right);
  1196. }
  1197.  
  1198. /* Pure brute force and ignorance */
  1199. int FindLongestBranches(dNode)
  1200. DependPtr dNode;
  1201. {
  1202.     int retVal, l, r;
  1203.  
  1204.     if (!dNode)
  1205.     {
  1206.     return 0;
  1207.     }
  1208.  
  1209.     if (dNode -> left || dNode -> right)
  1210.     {
  1211.     l = FindLongestBranches(dNode -> left);
  1212.     r = FindLongestBranches(dNode -> right);
  1213.     retVal = dNode -> longestBranch = 1 + (l > r ? l : r);
  1214.     }
  1215.     else
  1216.     {
  1217.     retVal = dNode -> longestBranch = 1;
  1218.     }
  1219.     return retVal;
  1220. }
  1221.  
  1222. Bool SetIndirectDependency(obj, var, dependObj, dependVar)
  1223. ObjPtr obj;
  1224. NameTyp var, dependObj, dependVar;
  1225. {
  1226.     DependPtr    tester;
  1227.     int        notfound;
  1228.  
  1229.     if (!obj)
  1230.     {
  1231.     return false;
  1232.     }
  1233.  
  1234.     /* search for variable in obj->depends */
  1235.     notfound = true;
  1236.     tester = obj->depends;
  1237.     if ( ! obj->depends)
  1238.     {
  1239.     obj->depends = NewDependNode(var); /* add first node */
  1240.     AddDependency(&(obj->depends->dependList), dependObj, dependVar);
  1241.     notfound = false;
  1242.     }
  1243.     while(notfound)
  1244.     {
  1245.     if (var == tester->var)
  1246.     {
  1247.         notfound = false;
  1248.         AddDependency(&(tester->dependList), dependObj, dependVar);
  1249.     }
  1250.     else if (var > tester->var)
  1251.     {
  1252.         if (tester->right)
  1253.         tester = tester->right;
  1254.         else                /* add node right */
  1255.         {
  1256.         tester->right = NewDependNode(var);
  1257.         AddDependency(&(tester->right->dependList), dependObj, dependVar);
  1258.         notfound = false;
  1259.         }
  1260.     }
  1261.     else                /* methodname < tester->name */
  1262.     {
  1263.         if (tester->left)
  1264.         tester = tester->left;
  1265.         else                /* add node left */
  1266.         {
  1267.         tester->left = NewDependNode(var);
  1268.         AddDependency(&(tester->left->dependList), dependObj, dependVar);
  1269.         notfound = false;
  1270.         }
  1271.     }
  1272.     }
  1273. #ifdef DEBUG
  1274.     fprintf(stderr, "# nodes %d, longest branch %d\n", CountNodes(obj->depends),
  1275.             FindLongestBranches(obj -> depends));
  1276. #endif
  1277.     return true;
  1278. }
  1279.  
  1280. Bool SetDependency(obj, var, dependVar)
  1281. ObjPtr obj;
  1282. NameTyp var, dependVar;
  1283. {
  1284.     return SetIndirectDependency(obj, var, 0, dependVar);
  1285. }
  1286.  
  1287. void GetDependencies(obj, var, callBack)
  1288. ObjPtr obj;
  1289. NameTyp var;
  1290. void (* callBack) (ObjPtr, NameTyp, NameTyp, NameTyp);
  1291. {
  1292.     ObjPtr classRunner;
  1293.     DependPtr tester;
  1294.     DLPtr runner;
  1295.  
  1296.     classRunner = obj;
  1297.  
  1298.     /* nothing happens if obj == nil; */
  1299.     while (classRunner)
  1300.     {
  1301.     tester = classRunner -> depends;
  1302.     while (tester && tester -> var != var)
  1303.     {
  1304.         if (tester -> var > var)
  1305.         {
  1306.         tester = tester -> left;
  1307.         }
  1308.         else
  1309.         {
  1310.         tester = tester -> right;
  1311.         }
  1312.     }
  1313.     if (tester)
  1314.     {
  1315.  
  1316.         runner = tester -> dependList;
  1317.         while (runner)
  1318.         {
  1319.         if (callBack)
  1320.         {
  1321.             (* callBack) (obj, var, runner->indirectVar, runner->var);
  1322.         }
  1323.         runner = runner -> next;
  1324.         }
  1325.     }
  1326.     classRunner = classRunner -> class;
  1327.     }
  1328. }
  1329.  
  1330. void PrintDependencies(obj, var)
  1331. ObjPtr obj;
  1332. NameTyp var;
  1333. {
  1334.     DependPtr depends;
  1335.     DLPtr dList;
  1336.  
  1337.     if (!obj) return;
  1338.  
  1339.     depends = obj -> depends;
  1340.     while (depends && depends -> var != var)
  1341.     {
  1342.     if (depends -> var > var)
  1343.         depends = depends -> left;
  1344.     else
  1345.         depends = depends -> right;
  1346.     }
  1347.  
  1348.     if (!depends)
  1349.     {
  1350.     return;
  1351.     }
  1352.  
  1353.     dList = depends -> dependList;
  1354.  
  1355.     while (dList)
  1356.     {
  1357.     if (dList -> indirectVar)
  1358.     {
  1359.         fprintf(stderr, "0x%x: var %s dependent on %s of %s\n", obj,
  1360.         IDName (var), IDName (dList->var), IDName (dList->indirectVar));
  1361.     }
  1362.     else
  1363.     {
  1364.         fprintf(stderr, "0x%x: var %s dependent on var %s\n", obj,
  1365.         IDName (var), IDName (dList->var));
  1366.     }
  1367.     dList = dList -> next;
  1368.     }
  1369.     fprintf(stderr, "going up one class\n");
  1370.     PrintDependencies(obj->class, var);
  1371.     fprintf(stderr, "trying to call GetDependencies\n");
  1372.     GetDependencies(obj, var, 0);
  1373. }
  1374.  
  1375. void PrintAllDependencies(obj)
  1376. ObjPtr obj;
  1377. {
  1378.     int i;
  1379.  
  1380.     if (!obj)
  1381.     {
  1382.     return;
  1383.     }
  1384.  
  1385.     fprintf(stderr, "\nPrinting all dependencies for obj 0x%x\n", obj);
  1386.  
  1387.     for (i = 0; i < 500; ++i)
  1388.     {
  1389.     PrintDependencies(obj, i);
  1390.     }
  1391.     fprintf(stderr, "Done printing dependencies for obj 0x%x\n\n", obj);
  1392. }
  1393.  
  1394. void    CloneMethodTreeInternal(obj, tree)
  1395. ObjPtr        obj;
  1396. MethodPtr    tree;
  1397. {
  1398.     if (tree)
  1399.     {
  1400.     SetMethod(obj, tree->name, tree->method);
  1401.     CloneMethodTreeInternal(obj, tree->left);
  1402.     CloneMethodTreeInternal(obj, tree->right);
  1403.     }
  1404. }
  1405.  
  1406. void    CloneMethods(target, src)
  1407. ObjPtr    target, src;
  1408. {
  1409.     CloneMethodTreeInternal(target, src->methods);
  1410. }
  1411.  
  1412. /**-- BORK routines specific to type INTEGER */
  1413.  
  1414. ObjPtr    NewInt(intno)
  1415. /* NewInt:    create a new Thing of type Int. Allocates necessary space */
  1416. int    intno;
  1417. {
  1418.     IPtr ip;
  1419.  
  1420.     if (!(ip = (IPtr) NewObject(NULLOBJ, sizeof(IntThing) - sizeof(Obj))))
  1421.     {
  1422.     OMErr();
  1423.     return NULLOBJ;
  1424.     }
  1425.     ip->thing.flags = INTEGER; /* it's "Not" an object */
  1426.  
  1427.     ip->intpart = intno;
  1428.     return (ObjPtr) ip;
  1429. }
  1430.  
  1431. int GetInt (ip)
  1432. ObjPtr ip;
  1433. {
  1434.     if (!ip)
  1435.     return 0;
  1436.     if (!IsInt(ip))
  1437.     {
  1438.     if (IsReal(ip))
  1439.         return ((RPtr) ip) -> realpart;
  1440.     else
  1441.     {
  1442.         ReportError("GetInt", "non-numeric thing!");
  1443.         return 0;
  1444.     }
  1445.     }
  1446.     return ((IPtr) ip) -> intpart;
  1447. }
  1448.  
  1449. void    SetInt (ip,intno)
  1450. /* SetInt:Sets the real number part of a Thing of type Int */
  1451. ObjPtr    ip;
  1452. int    intno;
  1453. {
  1454.     fprintf(stderr, "Don't use SetInt anymore, Bwana!\n");
  1455.     if (!ip)
  1456.     {
  1457.     ReportError("SetInt", "Null pointer!");
  1458.     }
  1459.     if (!IsInt(ip))
  1460.     {
  1461.     ReportError("SetInt", "Not an Int!");
  1462.     }
  1463.     ((IPtr) ip)->intpart = intno;
  1464. }
  1465.  
  1466. void    PrintInt(ip)
  1467. /* PrintInt: prints the contents of an int thing */
  1468. ObjPtr    ip;
  1469. {
  1470.     printf("&ip=%ld, intpart=%d\n",(long)ip,((IPtr)ip)->intpart);
  1471. }
  1472.  
  1473. /**-- routines specific to type Real */
  1474.  
  1475. /* NewReal: create a new Thing of type Real. Allocates necessary space. */
  1476. #ifdef PROTO
  1477. ObjPtr    NewReal(real realno)
  1478. #else
  1479. ObjPtr    NewReal(realno)
  1480. real    realno;
  1481. #endif
  1482. {
  1483.     RPtr    rp;
  1484.  
  1485.     if (!(rp = (RPtr) NewObject(NULLOBJ, sizeof(RealThing) - sizeof(Obj))))
  1486.     {
  1487.     OMErr();
  1488.     return NULLOBJ;
  1489.     }
  1490.     rp->thing.flags = REAL;
  1491.     /* fix the rest */
  1492.     rp->realpart = realno;
  1493.     return (ObjPtr) rp;
  1494. }
  1495.  
  1496. real GetReal(rp)
  1497. ObjPtr rp;
  1498. {
  1499.     if (!rp)
  1500.     return 0.0;
  1501.     if (!IsReal(rp))
  1502.     {
  1503.     if (IsInt(rp))
  1504.         return ((IPtr) rp) -> intpart;
  1505.     else
  1506.     {
  1507.         ReportError("GetReal", "non-numeric thing!");
  1508.         return 0.0;
  1509.     }
  1510.     }
  1511.     return ((RPtr) rp) -> realpart;
  1512. }
  1513.  
  1514. /* SetReal:Sets the real number part of a Thing of type Real */
  1515. #ifdef PROTO
  1516. void    SetReal(ObjPtr rp, real realno)
  1517. #else
  1518. void    SetReal(rp,realno)
  1519. ObjPtr    rp;
  1520. real    realno;
  1521. #endif
  1522. {
  1523.     fprintf(stderr, "Don't use SetReal anymore, Bwana!\n");
  1524.     if (!rp)
  1525.     {
  1526.     ReportError("SetReal", "Null pointer!");
  1527.     return;
  1528.     }
  1529.     if (!IsReal(rp))
  1530.     {
  1531.     ReportError("SetReal", "Not a Real!");
  1532.     return;
  1533.     }
  1534.     ((RPtr) rp)->realpart = realno;
  1535. }
  1536.  
  1537. void    PrintReal(rp)
  1538. /* PrintReal: prints the contents of a real thing */
  1539. ObjPtr    rp;
  1540. {
  1541.     printf("&rp=%ld, realpart=%f\n",(long)rp,((RPtr)rp)->realpart);
  1542. }
  1543.  
  1544. ObjPtr    NewString(string)
  1545. /* NewString: makes space for and sets up new Thing of type StringThing
  1546.  * NOTE: some of the contents of this routine are copied in ConcatString!
  1547.  */
  1548. char    *string;
  1549. {
  1550.     SPtr    sp;
  1551.  
  1552.     if (!(sp = (SPtr) NewObject(stringClass, sizeof(StringThing) - sizeof(Obj))))
  1553.     {
  1554.     OMErr();
  1555.     return NULLOBJ;
  1556.     }
  1557.     sp->thing.flags = STRING;
  1558.     if (!(sp->stringPtr = Alloc(strlen(string)+1) ))
  1559.     {
  1560.     OMErr();
  1561.     return NULLOBJ;
  1562.     }
  1563.     strcpy(sp->stringPtr,string);
  1564.     return (ObjPtr) sp;
  1565. }
  1566.  
  1567. ObjPtr    CleanupString(strObj)    /* CLEANUP method for string objects */
  1568. ObjPtr    strObj;
  1569. {
  1570.     if (!IsString(strObj))
  1571.     {
  1572.     ReportError("CleanupString", "got non-string object!");
  1573.     return ObjFalse;
  1574.     }
  1575.  
  1576.     if (! ((SPtr) strObj) -> stringPtr)
  1577.     {
  1578.     ReportError("CleanupString", "Tried to delete NIL");
  1579.     return ObjFalse;
  1580.     }
  1581.  
  1582.     Free (((SPtr) strObj) -> stringPtr);
  1583.     return ObjTrue;
  1584. }
  1585.  
  1586. char *GetString(sp)
  1587. ObjPtr sp;
  1588. {
  1589.     if (!sp)
  1590.     return (char *) 0;
  1591.     if (!IsString(sp))
  1592.     {
  1593.     ReportError("GetString", "non-string thing!");
  1594.     return (char *) 0;
  1595.     }
  1596.     return ((SPtr) sp) -> stringPtr;
  1597. }
  1598.  
  1599. Bool    SetString(sp,string)
  1600. /* SetString: resets the string value of a Thing of type StringThing. Allo-
  1601.     cates the necessary space, and frees space occupied by the old value */
  1602. ObjPtr    sp;
  1603. char    *string;
  1604. {
  1605.     if (!sp)
  1606.     {
  1607.     return false;
  1608.     }
  1609.     if (!IsString(sp))
  1610.     {
  1611.     ReportError("SetString", "Not a STRING!");
  1612.     }
  1613.     Free( ((SPtr)sp) -> stringPtr);
  1614.     if (!(((SPtr) sp) -> stringPtr = Alloc(strlen(string)+1)))
  1615.     {
  1616.     OMErr();
  1617.     return false;
  1618.     }
  1619.     strcpy(((SPtr) sp) -> stringPtr,string);
  1620. }
  1621.  
  1622. ObjPtr ConcatStrings(str1, str2)
  1623. ObjPtr str1, str2;
  1624. {
  1625.     SPtr sp;
  1626.     long int len;
  1627.  
  1628.     if (!str1 && !str2)
  1629.     {
  1630.     return NULLOBJ;
  1631.     }
  1632.  
  1633.     if (!IsString(str1) || !IsString(str2))
  1634.     {
  1635.     ReportError("ConcatStrings", "Not a STRING!");
  1636.     return NULLOBJ;
  1637.     }
  1638.  
  1639.     if (!str1 || !((SPtr)str1)->stringPtr || !*((SPtr)str1)-> stringPtr)
  1640.     /* str1 == NULLOBJ or str1->stringPtr == NIL or first character == \0 */
  1641.     {
  1642.     return Clone(str2);
  1643.     }
  1644.  
  1645.     if (!str2 || !((SPtr)str2)->stringPtr || !*((SPtr)str2)-> stringPtr)
  1646.     /* str2 == NULLOBJ or str2->stringPtr == NIL or first character == \0 */
  1647.     {
  1648.     return Clone(str1);
  1649.     }
  1650.  
  1651.     len = strlen(((SPtr)str1)->stringPtr) + strlen(((SPtr)str2)->stringPtr);
  1652.     if (!(sp = (SPtr)NewObject(stringClass,sizeof(StringThing) - sizeof(Obj))))
  1653.     {
  1654.         OMErr();
  1655.         return NULLOBJ;
  1656.     }
  1657.     sp->thing.flags = STRING;
  1658.     if (!(sp->stringPtr = Alloc(len+1) ))
  1659.     {
  1660.         OMErr();
  1661.         return NULLOBJ;
  1662.     }
  1663.     strcpy(sp->stringPtr,((SPtr)str1)->stringPtr);
  1664.     strcat(sp->stringPtr,((SPtr)str2)->stringPtr);
  1665.     return (ObjPtr) sp;
  1666. }
  1667.  
  1668. void    PrintString(sp)
  1669. /* PrintString: prints the contents of a string-thing */
  1670. ObjPtr    sp;
  1671. {
  1672.     if (!sp)
  1673.     {
  1674.     return;
  1675.     }
  1676.     else if (!(((SPtr) sp) -> stringPtr))
  1677.     {
  1678.     printf("PrintString: null pointer sp->stringPtr!\n");
  1679.     }
  1680.     else
  1681.     {
  1682.     printf("&sp=%ld, string=%s\n",(long)sp, ((SPtr) sp) -> stringPtr);
  1683.     }
  1684. }
  1685.  
  1686. #define THRESHOLD 10E-5
  1687.  
  1688. Bool    Eql(ObjPtr obj1, ObjPtr obj2)
  1689. {
  1690.     if (obj1 == NULLOBJ && obj2 == NULLOBJ)
  1691.     {
  1692.     return true;                /* two NULL ptrs are equal */
  1693.     }
  1694.     else if (obj1 == NULLOBJ || obj2 == NULLOBJ)
  1695.     {
  1696.     return false;            /* one NULL, one nonNULL are not */
  1697.     }
  1698.     else if (OBJTYPE(obj1->flags) != OBJTYPE(obj2->flags))
  1699.     {
  1700.     if (IsReal(obj1) && IsInt(obj2))
  1701.     {
  1702.         int i; real r;
  1703.  
  1704.         r = GetReal(obj1); i = GetInt(obj2);
  1705.         if (abs(i - r) < abs(r * THRESHOLD))
  1706.         return true;
  1707.         else
  1708.         return false;
  1709.     }
  1710.     else if (IsReal(obj2) && IsInt(obj1))
  1711.     {
  1712.         int i; real r;
  1713.  
  1714.         r = GetReal(obj2); i = GetInt(obj1);
  1715.         if (abs(i - r) < abs(r * THRESHOLD))
  1716.         return true;
  1717.         else
  1718.         return false;
  1719.     }
  1720.     else
  1721.     {
  1722.         return false;    /* flags indicate incomparable things */
  1723.     }
  1724.     }
  1725.     else    /* now we have two non-null ptrs with identical type */
  1726.     {
  1727.     switch (OBJTYPE(obj1 -> flags))
  1728.     {
  1729.         case REAL:
  1730.         return GetReal(obj1) == GetReal(obj2);
  1731.         break;
  1732.         case INTEGER:
  1733.         return GetInt(obj1) == GetInt(obj2);
  1734.         break;
  1735.         case STRING:
  1736.         {
  1737.             char tempStr1[TEMPSTRSIZE], tempStr2[TEMPSTRSIZE];
  1738.  
  1739.             strncpy(tempStr1, GetString(obj1), TEMPSTRSIZE);
  1740.             strncpy(tempStr2, GetString(obj2), TEMPSTRSIZE);
  1741.             return 0 == strcmp(tempStr1, tempStr2);
  1742.         }
  1743.         break;
  1744.         case ISOBJECT:
  1745.         case REALARRAY:
  1746.         case LIST:
  1747.         case PALETTE:
  1748.         case WINDOW:
  1749.         case PICTURE:
  1750.         return obj1 == obj2;
  1751.         break;
  1752.         default:
  1753.         return obj1 == obj2; /* unknown type, but compare ptrs anyway */
  1754.         break;
  1755.     }
  1756.     }
  1757. }
  1758.  
  1759. Bool    Equal(ObjPtr obj1, ObjPtr obj2)
  1760. /* Equal: two things are defined to be Equal if and only if a) the pointers
  1761.     are the same, b) the things are of the same type, and are of
  1762.     (internal) type Integer, Real or String, and have the same values.
  1763.     (as of 6-19-91 this is functionally identical to Eql) */
  1764. {
  1765.     if (obj1 == NULLOBJ && obj2 == NULLOBJ)
  1766.     {
  1767.     return true;                /* two NULL ptrs are equal */
  1768.     }
  1769.     else if (obj1 == NULLOBJ || obj2 == NULLOBJ)
  1770.     {
  1771.     return false;            /* one NULL, one nonNULL are not */
  1772.     }
  1773.     else if (obj1->flags != obj2->flags)
  1774.     {
  1775.     if (obj1 -> flags == REAL && obj2 -> flags == INTEGER)
  1776.     {
  1777.         int i; real r;
  1778.  
  1779.         r = GetReal(obj1); i = GetInt(obj2);
  1780.         if (abs(i - r) < abs(r * THRESHOLD))
  1781.         return true;
  1782.         else
  1783.         return false;
  1784.     }
  1785.     else if (obj2 -> flags == REAL && obj1 -> flags == INTEGER)
  1786.     {
  1787.         int i; real r;
  1788.  
  1789.         r = GetReal(obj2); i = GetInt(obj1);
  1790.         if (abs(i - r) < abs(r * THRESHOLD))
  1791.         return true;
  1792.         else
  1793.         return false;
  1794.     }
  1795.     else
  1796.     {
  1797.         return false;    /* if flags indicate incomparable things */
  1798.     }
  1799.     }
  1800.     else    /* now we have two non-null ptrs with identical flags */
  1801.     {
  1802.     switch (obj1 -> flags)
  1803.     {
  1804.         case REAL:
  1805.         return GetReal(obj1) == GetReal(obj2);
  1806.         break;
  1807.         case INTEGER:
  1808.         return GetInt(obj1) == GetInt(obj2);
  1809.         break;
  1810.         case STRING:
  1811.         {
  1812.             char tempStr1[TEMPSTRSIZE], tempStr2[TEMPSTRSIZE];
  1813.  
  1814.             strncpy(tempStr1, GetString(obj1), TEMPSTRSIZE);
  1815.             strncpy(tempStr2, GetString(obj2), TEMPSTRSIZE);
  1816.             return 0 == strcmp(tempStr1, tempStr2);
  1817.         }
  1818.         break;
  1819.         default:
  1820.         return obj1 == obj2; /* unknown type, but compare ptrs anyway */
  1821.         break;
  1822.     }
  1823.     }
  1824. }
  1825.  
  1826. ObjPtr    Clone(obj)
  1827. ObjPtr    obj;
  1828. {
  1829.     ObjPtr retVal = NULLOBJ;
  1830.     if (!obj)
  1831.     {
  1832.     return NULLOBJ;
  1833.     }
  1834.     switch(OBJTYPE(obj->flags))
  1835.     {
  1836.     case ISOBJECT:
  1837.         retVal = NewObject(obj->class, 0);
  1838.         break;
  1839.     case REALARRAY:
  1840.         ReportError("Clone", "can't clone type REALARRAY!");
  1841.         break;
  1842.     case STRING:
  1843.         retVal = NewString( ((SPtr) obj) -> stringPtr);
  1844.         retVal -> class = obj -> class;
  1845.         break;
  1846.     case INTEGER:
  1847.         retVal = NewInt(GetInt(obj));
  1848.         retVal -> class = obj -> class;
  1849.         break;
  1850.     case REAL:
  1851.         retVal = NewReal(GetReal(obj));
  1852.         retVal -> class = obj -> class;
  1853.         break;
  1854.     case LIST:
  1855.         ReportError("Clone", "can't clone type LIST!");
  1856.         break;
  1857.     case PALETTE:
  1858.         retVal = ClonePalette(obj);
  1859.         retVal -> class = obj -> class;
  1860.         break;
  1861.     case WINDOW:
  1862.         ReportError("Clone", "can't clone type WINDOW!");
  1863.         break;
  1864.     case PICTURE:
  1865.         ReportError("Clone", "can't clone type PICTURE!");
  1866.         break;
  1867.     default:
  1868.         ReportError("Clone", "unknown flag type!");
  1869.         break;
  1870.     }
  1871.     if (retVal)
  1872.     {
  1873.     CloneVars(retVal, obj);
  1874.     CloneMethods(retVal, obj);
  1875.     }
  1876.     return retVal;
  1877. }
  1878.  
  1879. /* sets up objClass, the class to which all things belong */
  1880. void InitObjects()
  1881. {
  1882.  
  1883.     if (getenv("SCIAN_DEBUG_COUNT_OBJECTS"))
  1884.     {
  1885.     int i;
  1886.  
  1887.     debugCountObjects = 1;
  1888.     extras = Alloc(sizeof(unsigned long) * MAXEXTRA);
  1889.  
  1890.     fprintf(stderr, "size of basic object structure = %d\n", sizeof(Obj));
  1891.  
  1892.     for (i = 0; i < MAXEXTRA; ++i)
  1893.         *(extras + i) = 0;
  1894.     }
  1895.  
  1896. #if 0
  1897.     /* note that NetworkStub and NetworkUpdated really have no class */
  1898.     NetworkStub = NewObject(0,0);
  1899.     NetworkStub -> flags = 0;    /* make sure nothing works on this thing. */
  1900.     AddToReferenceList(NetworkStub);
  1901.     NetworkUpdated = NewObject(0,0);
  1902.     NetworkUpdated -> flags = 0;
  1903.     AddToReferenceList(NetworkUpdated);
  1904.     NetworkWaiting = NewObject(0,0);
  1905.     NetworkWaiting -> flags = 0;
  1906.     AddToReferenceList(NetworkWaiting);
  1907. #endif
  1908.  
  1909.     objClass = NewObject(NULLOBJ, 0);
  1910.     AddToReferenceList(objClass);
  1911.     SetMethod(objClass, SETVAL, SetObjValue);
  1912.     SetMethod(objClass, GETVAL, GetObjValue);
  1913.     SetMethod(objClass, PICKUP, PickUpObject);
  1914.  
  1915.     ObjTrue = NewInt(1);
  1916.     AddToReferenceList(ObjTrue);
  1917.  
  1918.  
  1919.     stringClass = NewObject(NULLOBJ, 0);
  1920.     AddToReferenceList(stringClass);
  1921.     SetMethod(stringClass, CLEANUP, CleanupString);
  1922.  
  1923.     InitNetObjects();
  1924.  
  1925.     InitXYControls();
  1926. }
  1927.  
  1928. void KillObjects()
  1929. {
  1930.     int i;
  1931.  
  1932.     KillXYControls();
  1933.     KillNetObjects();
  1934.     RemoveFromReferenceList(objClass);
  1935.     RemoveFromReferenceList(ObjTrue);
  1936.     TrashDay();
  1937.  
  1938.     if (debugCountObjects)
  1939.     {
  1940.     for (i = 0; i < MAXEXTRA - 1; ++i)
  1941.         if (*(extras + i) != 0)
  1942.         fprintf(stderr, "# objects with %d extra bytes: %ld\n", i, *(extras + i));
  1943.  
  1944.     if (*(extras + MAXEXTRA - 1) != 0)
  1945.         fprintf(stderr, "# objects with %d or more extra bytes: %ld\n", MAXEXTRA - 1, *(extras + i));
  1946.     fprintf(stderr, "most extra bytes in one object is %ld\n", maxExtra);
  1947.     }
  1948. }
  1949.  
  1950. Bool SanityCheckObject(obj)
  1951. ObjPtr obj;
  1952. {
  1953.     Bool retVal = true;
  1954.  
  1955.     if (!obj) /* NULLOBJ is ok */
  1956.     {
  1957.     return true;
  1958.     }
  1959.  
  1960.     /* too bad there's no way to check for a segmentation fault. */
  1961.     if (OBJTYPE(obj->flags) < 0 || OBJTYPE(obj -> flags) > HIGHESTFLAG)
  1962.     {
  1963.     retVal = false;
  1964.     fprintf(stderr, "bad obj type %d\n", OBJTYPE(obj -> flags));
  1965.     }
  1966.  
  1967.     if (obj->flags & ~(OBJTYPEFLAGS | ISREMOTE | ISPUBLISHED | ISWAITING | ISREMOTEADVERTISED))
  1968.     {
  1969.     retVal = false;
  1970.     fprintf(stderr, "funny flags = 0x%lx\n", obj -> flags);
  1971.     }
  1972.  
  1973.     if (!retVal)
  1974.     {
  1975.     char str[100];
  1976.  
  1977.     sprintf(str, "Object failed Sanity Check! flags = %lx", obj->flags);
  1978.     ReportError("SanityCheckObject", str);
  1979.     }
  1980.     return retVal;
  1981. }
  1982.